package com.william.jdbcplus.core.dialect.ddl.util;

import com.william.jdbcplus.common.enums.DbType;
import com.william.jdbcplus.core.dialect.ddl.column.ColumnFactory;
import com.william.jdbcplus.core.dialect.ddl.column.IColumn;
import com.william.jdbcplus.core.dialect.ddl.util.model.TableMeta;
import com.william.jdbcplus.core.meta.TableColumnInfo;
import com.william.jdbcplus.core.meta.TableInfo;
import com.william.jdbcplus.core.util.JdbcExecUtil;
import com.william.jdbcplus.core.util.datameta.TableMetaColumnInfo;

import javax.sql.DataSource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字段处理
 *
 * @author niliwei
 */
public class ColumnUtil {
    /**
     * 检查列是否一致
     *
     * @param dbType    数据库类型
     * @param tableMeta 表信息
     * @return
     */
    public static List<String> check(DbType dbType, TableMeta tableMeta) {
        List<String> errList = new LinkedList<>();
        List<TableMetaColumnInfo> columnList = tableMeta.getTableMeta().getColumnList();
        Map<String, TableMetaColumnInfo> columnInfoMap = columnList.stream().collect(Collectors.toMap(e -> e.getColumnName().toLowerCase(), e -> e));
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableColumnInfo> colList = tableInfo.getColumnList();
        IColumn iColumn = ColumnFactory.getInstance(dbType);
        for (TableColumnInfo fieldInfo : colList) {
            if (columnInfoMap.containsKey(fieldInfo.getColumn().toLowerCase())) {
                TableMetaColumnInfo columnInfo = columnInfoMap.get(fieldInfo.getColumn().toLowerCase());
                // 数据表中列已经存在而且与实例不一致
                if (!iColumn.match(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                    if (!iColumn.matchTypeName(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                        errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fieldInfo.getColumn() + " 类型不正确");
                    }
                    if (!iColumn.matchLength(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                        errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fieldInfo.getColumn() + " 长度不正确");
                    }
                    if (!iColumn.matchDigits(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                        errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fieldInfo.getColumn() + " 小数位数不正确");
                    }
                    if (!iColumn.matchNullable(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                        errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fieldInfo.getColumn() + " 非空约束不正确");
                    }
                }
            } else {
                // 数据表中列不存在
                errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fieldInfo.getColumn() + " 不存在");
            }
        }

        return errList;
    }

    /**
     * 更新字段结构
     *
     * @param dbType    数据库类型
     * @param tableMeta 实体表结构信息
     * @param ds        数据源
     * @return
     */
    public static void update(DbType dbType, TableMeta tableMeta, DataSource ds) {
        List<TableMetaColumnInfo> columnList = tableMeta.getTableMeta().getColumnList();
        Map<String, TableMetaColumnInfo> columnInfoMap = columnList.stream().collect(Collectors.toMap(e -> e.getColumnName().toLowerCase(), e -> e));
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableColumnInfo> colList = tableInfo.getColumnList();
        IColumn iColumn = ColumnFactory.getInstance(dbType);
        for (TableColumnInfo fieldInfo : colList) {
            if (columnInfoMap.containsKey(fieldInfo.getColumn().toLowerCase())) {
                TableMetaColumnInfo columnInfo = columnInfoMap.get(fieldInfo.getColumn().toLowerCase());
                // 数据表中列已经存在而且与实例不一致, 则修改列
                if (!iColumn.match(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                    String sql = iColumn.modify(tableMeta.getClazz(), fieldInfo, columnInfo);
                    //修改字段不成功，则要重建表字段
                    boolean success = JdbcExecUtil.execOne(sql, ds);
                    if (!success) {
                        sql = iColumn.rebuild(tableMeta.getClazz(), fieldInfo, columnInfo);
                        JdbcExecUtil.execBreak(sql, ds);
                    }
                }
            } else {
                // 数据表中列不存在，则新增列
                String sql = iColumn.add(tableMeta.getClazz(), fieldInfo);
                JdbcExecUtil.execOne(sql, ds);
            }
        }
    }

    /**
     * 获取字段更新脚本列表
     *
     * @param dbType
     * @param tableMeta
     * @return
     */
    public static List<String> getUpdateSQL(DbType dbType, TableMeta tableMeta) {
        List<String> sqlList = new LinkedList<>();
        List<TableMetaColumnInfo> columnList = tableMeta.getTableMeta().getColumnList();
        Map<String, TableMetaColumnInfo> columnInfoMap = columnList.stream().collect(Collectors.toMap(e -> e.getColumnName().toLowerCase(), e -> e));
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableColumnInfo> colList = tableInfo.getColumnList();
        IColumn iColumn = ColumnFactory.getInstance(dbType);
        for (TableColumnInfo fieldInfo : colList) {
            if (columnInfoMap.containsKey(fieldInfo.getColumn().toLowerCase())) {
                TableMetaColumnInfo columnInfo = columnInfoMap.get(fieldInfo.getColumn().toLowerCase());
                // 数据表中列已经存在而且与实例不一致, 则修改列
                if (!iColumn.match(tableMeta.getClazz(), fieldInfo, columnInfo)) {
                    String sql = iColumn.modify(tableMeta.getClazz(), fieldInfo, columnInfo);
                    sqlList.add(sql);
                }
            } else {
                // 数据表中列不存在，则新增列
                String sql = iColumn.add(tableMeta.getClazz(), fieldInfo);
                sqlList.add(sql);
            }
        }

        return sqlList;
    }
}
